<script setup lang="ts">
import type TreeNodeProp from "@/components/tree/TreeNodeProp.ts";
import {computed, onMounted, onUnmounted, ref, toRaw} from "vue";

const emit = defineEmits<{
  (e: 'checked', node: string, checked: boolean): void
}>()
const props = defineProps<{
  node: TreeNodeProp,
  checkedKeys: string[],
  checkStrategy?: (node: TreeNodeProp) => boolean,
  check?: boolean,
  allCheck?: boolean,
  cancelCheck?: boolean,
  recursiveCheck?: boolean,
  loadChildren?: (node: TreeNodeProp) => Promise<TreeNodeProp[]>,
  defaultExpanded?: boolean
}>();

const expanded = ref(toRaw(props.defaultExpanded))
const loading = ref(false)

const checkedValue = ref(false)

const checked = computed<boolean>({
  get: () => {
    return props.checkedKeys?.includes(props.node.id) ?? checkedValue.value
  },
  set: (val: boolean) => {
    // 内部状态始终更新，保证不传 checkedKeys 也能选中
    checkedValue.value = val

    // 如果传了 checkedKeys，就操作它
    if (props.checkedKeys) {
      const idx = props.checkedKeys.indexOf(props.node.id)
      if (val && idx === -1) {
        props.checkedKeys.push(props.node.id)
      } else if (!val && idx !== -1) {
        props.checkedKeys.splice(idx, 1)
      }
    }

    // 统一通知父组件
    emit("checked", props.node.id, val)
  }
})


const toggle = async () => {
  if (!expanded.value) {
    if (!(props.node.children && props.node.children.length > 0) && props.node.hasChildren) {
      if (props.loadChildren) {
        loading.value = true;
        props.node.children = await props.loadChildren(props.node);
        loading.value = false;
      } else {
        console.warn("未传loadChildren函数，无法加载子数据")
      }
    }
  }
  expanded.value = !expanded.value;
}

const updateCheckedRecursive = (node: TreeNodeProp, checked: boolean) => {
  if (props.checkedKeys) {
    const idx = props.checkedKeys.indexOf(node.id)
    if (checked && idx === -1) {
      props.checkedKeys.push(node.id)
    } else if (!checked && idx !== -1) {
      props.checkedKeys.splice(idx, 1)
    }
  }
  checkedValue.value = checked
  emit('checked', node.id, checked)

  //子节点递归处理
  if (node.children && node.children.length > 0) {
    node.children.forEach(child => updateCheckedRecursive(child, checked))
  }
}

const invertCheckedRecursive = (node: TreeNodeProp) => {
  const isChecked = props.checkedKeys.includes(node.id)
  const newChecked = !isChecked

  // 设置当前节点
  const idx = props.checkedKeys.indexOf(node.id)
  if (newChecked && idx === -1) {
    props.checkedKeys.push(node.id)
  } else if (!newChecked && idx !== -1) {
    props.checkedKeys.splice(idx, 1)
  }

  checkedValue.value = newChecked
  emit("checked", node.id, newChecked)

  // 递归子节点
  if (node.children && node.children.length > 0) {
    node.children.forEach(child => invertCheckedRecursive(child))
  }
}

onMounted(() => {
  if (props.checkStrategy && props.checkStrategy(props.node)) {
    props.checkedKeys.push(props.node.id)
  }
})

onUnmounted(() => {
  checkedValue.value = false
})

</script>

<template>
  <div class="tree-node">
    <div class="tree-label" @click="toggle">
      <!-- 箭头 -->
      <span class="arrow-wrapper">
        <span v-if="node.hasChildren" class="label-arrow" :class="{ expanded }">
          <component is="right"/>
        </span>
      </span>

      <!-- 主体 -->
      <span class="main-body">
        <input v-if="check" class="node-check" type="checkbox" v-model="checked" @click.stop/>
        <span>{{ node.key }}</span>
      </span>

      <!-- 可选按钮 -->
      <div class="node-btn">
        <t-btn v-if="allCheck" text pageSize="tiny" @click.stop="updateCheckedRecursive(node, true)">全选</t-btn>
        <t-btn v-if="cancelCheck" text pageSize="tiny" @click.stop="updateCheckedRecursive(node, false)">取消</t-btn>
        <t-btn v-if="recursiveCheck" text pageSize="tiny" @click.stop="invertCheckedRecursive(node)">反选</t-btn>
      </div>

    </div>

    <transition name="tree-expand">
      <div v-if="expanded && node.children?.length" class="tree-children">
        <TreeNode
            v-for="child in node.children"
            :key="child.id"
            :node="child"
            :loadChildren="loadChildren"
            :checkedKeys="checkedKeys"
            :checkStrategy="checkStrategy"
            :check="check"
            :allCheck="allCheck"
            :cancelCheck="cancelCheck"
            :recursiveCheck="recursiveCheck"
            :defaultExpanded="defaultExpanded"
            @checked="(id, checkStatus) => emit('checked', id, checkStatus)"
        />
      </div>
    </transition>
  </div>
</template>

<style scoped>
.tree-node {
  font-size: 14px;
  color: #333;
  user-select: none;
}

.tree-label {
  display: flex;
  align-items: center;
  padding: 4px 8px;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.tree-label:hover {
  background-color: #f2f4f7;
}

.arrow-wrapper {
  width: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-right: 4px;
}

.label-arrow {
  display: inline-block;
  transition: transform 0.2s ease;
  font-size: 12px;
  color: #888;
}

.label-arrow.expanded {
  transform: rotate(90deg);
}

.node-check {
  margin-left: 5px;
  margin-right: 5px;
}

.main-body {
  flex: 1;
}

.node-btn {

  display: flex;
  justify-content: end;
}

.loading-text {
  font-size: 12px;
  color: #aaa;
  margin-left: 8px;
}

/* 子树缩进 + 连接感 */
.tree-children {
  margin-left: 10px;
  border-left: 1px dashed #ccc;
  padding-left: 8px;
}

/* 展开动画 */
.tree-expand-enter-from,
.tree-expand-leave-to {
  opacity: 0;
  max-height: 0;
  transform: translateY(-4px);
}

.tree-expand-enter-active,
.tree-expand-leave-active {
  transition: all 0.2s ease;
}

.tree-expand-enter-to,
.tree-expand-leave-from {
  opacity: 1;
  max-height: 1000px;
  transform: translateY(0);
}
</style>
